package com.sh.data.engine.application.service.datadev;

import com.sh.data.engine.application.model.dto.datadev.OfflineDevApiHttpResponse;
import com.sh.data.engine.application.model.dto.datadev.OfflineDevApiWsResponse;
import com.sh.data.engine.application.model.dto.integration.*;
import com.sh.data.engine.application.model.mapper.integration.ApiTaskConfigConvert;
import com.sh.data.engine.application.model.request.datadev.OfflineDevApiHttpTaskSaveRequest;
import com.sh.data.engine.application.model.request.datadev.OfflineDevApiWsTaskSaveRequest;
import com.sh.data.engine.application.model.request.integration.*;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.datadev.offline.model.domain.OfflineDevApiDomain;
import com.sh.data.engine.domain.datadev.offline.model.enums.OfflineDevApiNodeTypeEnum;
import com.sh.data.engine.domain.datadev.offline.service.DatadevJobService;
import com.sh.data.engine.domain.datadev.offline.service.OfflineDevMenuNodeService;
import com.sh.data.engine.domain.integration.api.http.model.domain.TaskDomain;
import com.sh.data.engine.domain.integration.api.http.model.domain.TestApiHttpDomain;
import com.sh.data.engine.domain.integration.api.http.model.param.ApiHttpAuthParam;
import com.sh.data.engine.domain.integration.api.http.model.param.ApiHttpRequestBodyParam;
import com.sh.data.engine.domain.integration.api.http.model.param.TestApiHttpParam;
import com.sh.data.engine.domain.integration.api.http.service.ApiHttpService;
import com.sh.data.engine.domain.integration.api.taskconfig.model.domain.JarUploadResultDomain;
import com.sh.data.engine.domain.integration.api.taskconfig.model.domain.TaskConfigDomain;
import com.sh.data.engine.domain.integration.api.taskconfig.model.param.ExpressionParam;
import com.sh.data.engine.domain.integration.api.taskconfig.model.param.PreviewExpressParam;
import com.sh.data.engine.domain.integration.api.taskconfig.service.TaskConfigService;
import com.sh.data.engine.domain.integration.api.webservice.model.domain.GetServiceDomain;
import com.sh.data.engine.domain.integration.api.webservice.model.param.ApiWsAuthParam;
import com.sh.data.engine.domain.integration.api.webservice.model.param.ApiWsRequestBodyParam;
import com.sh.data.engine.domain.integration.api.webservice.model.param.GetServiceParam;
import com.sh.data.engine.domain.integration.api.webservice.model.param.TestApiWsParam;
import com.sh.data.engine.domain.integration.api.webservice.service.ApiWsService;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceDomain;
import com.sh.data.engine.domain.shims.db.model.FieldInfoDomain;
import com.sh.data.engine.domain.shims.db.model.TableInfoDomain;
import com.sh.data.engine.domain.util.ConvertUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Objects;

/**
 * @author: mengzheng.mhc
 * @date: 2024/7/29 14:14
 */
@Slf4j
@Service
public class OfflineDevApiApplicationService {

    @Autowired
    private OfflineDevMenuNodeService offlineDevMenuNodeService;

    @Autowired
    private DatadevJobService datadevJobService;

    @Autowired
    private ApiHttpService apiHttpService;

    @Autowired
    private ApiWsService apiWsService;

    @Autowired
    private TaskConfigService taskConfigServiceImpl;

    public OfflineDevApiHttpResponse getTaskById(Long id) {
        OfflineDevApiDomain taskDomain = offlineDevMenuNodeService.getOfflineDevApiDomainByNodeId(id);
        if (null == taskDomain) {
            return null;
        }

        TaskConfigDomain sourceTaskConfigRequest = taskDomain.getTaskConfigDomain();

        OfflineDevApiHttpResponse.TaskConfigRequest taskConfigRequest =
            ConvertUtil.copyProperties(
                sourceTaskConfigRequest, OfflineDevApiHttpResponse.TaskConfigRequest.class);

        taskConfigRequest.setTargetFields(
            ConvertUtil.copyProperties(
                sourceTaskConfigRequest.getTargetFields(),
                OfflineDevApiHttpResponse.TaskConfigRequest.TargetField.class));
        taskConfigRequest.setFieldMappings(
            ConvertUtil.copyProperties(
                sourceTaskConfigRequest.getFieldMappings(),
                OfflineDevApiHttpResponse.TaskConfigRequest.FieldMapping.class));
        taskConfigRequest.setPartitions(
            ConvertUtil.copyProperties(
                sourceTaskConfigRequest.getPartitions(),
                OfflineDevApiHttpResponse.TaskConfigRequest.PartitionField.class));

        OfflineDevApiHttpResponse offlineDevApiResponse = new OfflineDevApiHttpResponse();
        offlineDevApiResponse.setTaskConfigRequest(taskConfigRequest);

        offlineDevApiResponse.setApiHttpRequest(taskDomain.getOfflineDevApiHttpParam());
        offlineDevApiResponse.setNodeId(taskDomain.getNodeId());
        offlineDevApiResponse.setNodeName(taskDomain.getNodeName());
        offlineDevApiResponse.setProjectId(taskDomain.getProjectId());
        offlineDevApiResponse.setTaskName(taskDomain.getTaskName());
        offlineDevApiResponse.setRemark(taskDomain.getRemark());
        offlineDevApiResponse.setApiNodeType(OfflineDevApiNodeTypeEnum.HTTP.getNodeDesc());
        offlineDevApiResponse.setPreviewExpressRequest(taskDomain.getPreviewExpressRequest());
        return offlineDevApiResponse;
    }

    public OfflineDevApiWsResponse getWsTaskById(Long id) {
        OfflineDevApiDomain taskDomain = offlineDevMenuNodeService.getOfflineDevApiDomainByNodeId(id);
        if (null == taskDomain) {
            return null;
        }

        TaskConfigDomain sourceTaskConfigRequest = taskDomain.getTaskConfigDomain();

        OfflineDevApiWsResponse.TaskConfigRequest taskConfigRequest =
            ConvertUtil.copyProperties(
                sourceTaskConfigRequest, OfflineDevApiWsResponse.TaskConfigRequest.class);
        // 给前端回显返回值left pad 0
        taskConfigRequest.setTargetFields(
            ConvertUtil.copyProperties(
                sourceTaskConfigRequest.getTargetFields(),
                OfflineDevApiWsResponse.TaskConfigRequest.TargetField.class));
        taskConfigRequest.setFieldMappings(
            ConvertUtil.copyProperties(
                sourceTaskConfigRequest.getFieldMappings(),
                OfflineDevApiWsResponse.TaskConfigRequest.FieldMapping.class));
        taskConfigRequest.setPartitions(
            ConvertUtil.copyProperties(
                sourceTaskConfigRequest.getPartitions(),
                OfflineDevApiWsResponse.TaskConfigRequest.PartitionField.class));

        OfflineDevApiWsResponse offlineDevApiResponse = new OfflineDevApiWsResponse();
        offlineDevApiResponse.setTaskConfigRequest(taskConfigRequest);

        offlineDevApiResponse.setApiWsRequest(taskDomain.getOfflineDevApiWsParam());
        offlineDevApiResponse.setNodeId(taskDomain.getNodeId());
        offlineDevApiResponse.setNodeName(taskDomain.getNodeName());
        offlineDevApiResponse.setProjectId(taskDomain.getProjectId());
        offlineDevApiResponse.setTaskName(taskDomain.getTaskName());
        offlineDevApiResponse.setRemark(taskDomain.getRemark());
        offlineDevApiResponse.setApiNodeType(OfflineDevApiNodeTypeEnum.WS.getNodeDesc());
        offlineDevApiResponse.setPreviewExpressRequest(taskDomain.getPreviewExpressRequest());
        return offlineDevApiResponse;
    }

    public boolean saveTask(OfflineDevApiHttpTaskSaveRequest saveTaskRequest) {
        TestApiHttpRequest apiHttpRequest = saveTaskRequest.getApiHttpRequest();
        // 参数转换 请求参数
        TestApiHttpParam testApiHttpParam =
            ConvertUtil.copyProperties(apiHttpRequest, TestApiHttpParam.class);

        // 复制认证参数
        ApiHttpAuthParam apiHttpAuthParam =
            ConvertUtil.copyProperties(apiHttpRequest.getApiHttpAuthParam(), ApiHttpAuthParam.class);
        testApiHttpParam.setApiHttpAuthParam(apiHttpAuthParam);

        // 如果请求体设置了x-www-form-urlencoded, 进行复制
        TestApiHttpRequest.ApiHttpRequestBodyParam sourceBodyParam =
            apiHttpRequest.getApiHttpRequestBodyParam();
        ApiHttpRequestBodyParam apiHttpRequestBodyParam =
            ConvertUtil.copyProperties(sourceBodyParam, ApiHttpRequestBodyParam.class);
        if (CollectionUtils.isNotEmpty(sourceBodyParam.getFormParams())) {
            apiHttpRequestBodyParam.setFormParams(
                ConvertUtil.copyProperties(
                    sourceBodyParam.getFormParams(), ApiHttpRequestBodyParam.FormParam.class));
        }
        String jsonBody = apiHttpRequestBodyParam.getBody();
        if (StringUtils.isNotEmpty(jsonBody)) {
            apiHttpRequestBodyParam.setBody(jsonBody.replace("\r\n", ""));
        }
        testApiHttpParam.setApiHttpRequestBodyParam(apiHttpRequestBodyParam);

        // 用户填写的js脚本或者json path
        PreviewExpressRequest previewExpressRequest = saveTaskRequest.getPreviewExpressRequest();
        boolean existJsScript = StringUtils.isNotBlank(previewExpressRequest.getJsScript());
        boolean existJsonPath =
            CollectionUtils.isNotEmpty(previewExpressRequest.getExpressionParamList());
        if (existJsScript == existJsonPath) {
            throw new BusinessException("js脚本和json path必须填写并且只能填写一个");
        }

        TaskDomain.PreviewExpressRequest previewExpressParam =
            ConvertUtil.copyProperties(previewExpressRequest, TaskDomain.PreviewExpressRequest.class);
        // 如果填写的是jsonpath,进行复制
        if (existJsonPath) {
            previewExpressParam.setExpressionParamList(
                ConvertUtil.copyProperties(
                    previewExpressRequest.getExpressionParamList(),
                    TaskDomain.PreviewExpressRequest.ExpressionParam.class));
        }

        // 任务其他配置
        TaskConfigRequest taskConfigRequest = saveTaskRequest.getTaskConfigRequest();
        TaskConfigDomain taskConfigDomain =
            ApiTaskConfigConvert.convertTaskConfigDomain(taskConfigRequest);
        if (CollectionUtils.isNotEmpty(taskConfigRequest.getTargetFields())) {
            taskConfigDomain.setTargetFields(
                ConvertUtil.copyProperties(
                    taskConfigRequest.getTargetFields(), TaskConfigDomain.TargetField.class));
        }
        if (CollectionUtils.isNotEmpty(taskConfigRequest.getFieldMappings())) {
            taskConfigDomain.setFieldMappings(
                ConvertUtil.copyProperties(
                    taskConfigRequest.getFieldMappings(), TaskConfigDomain.FieldMapping.class));
        }
        if (CollectionUtils.isNotEmpty(taskConfigRequest.getPartitions())) {
            taskConfigDomain.setPartitions(
                ConvertUtil.copyProperties(
                    taskConfigRequest.getPartitions(), TaskConfigDomain.PartitionField.class));
        }

        OfflineDevApiDomain offlineDevApiDomain = new OfflineDevApiDomain();
        offlineDevApiDomain.setOfflineDevApiHttpParam(testApiHttpParam);
        offlineDevApiDomain.setApiNodeType(OfflineDevApiNodeTypeEnum.HTTP.getNodeDesc());
        offlineDevApiDomain.setTaskConfigDomain(taskConfigDomain);
        offlineDevApiDomain.setPreviewExpressRequest(previewExpressParam);
        offlineDevApiDomain.setNodeId(saveTaskRequest.getNodeId());
        offlineDevApiDomain.setNodeName(saveTaskRequest.getNodeName());
        offlineDevApiDomain.setTaskName(saveTaskRequest.getTaskName());
        offlineDevApiDomain.setProjectId(ServletUtils.getProjectId());
        offlineDevMenuNodeService.saveOrUpdateOfflineApiTask(offlineDevApiDomain);
        return true;
    }

    public boolean saveTask(OfflineDevApiWsTaskSaveRequest saveTaskRequest) {
        TestApiWsRequest apiWsRequest = saveTaskRequest.getApiWsRequest();
        // 参数转换 请求参数
        TestApiWsParam testApiWsParam = ConvertUtil.copyProperties(apiWsRequest, TestApiWsParam.class);

        // 复制认证参数
        ApiWsAuthParam apiWsAuthParam =
            ConvertUtil.copyProperties(apiWsRequest.getApiWsAuthParam(), ApiWsAuthParam.class);
        testApiWsParam.setApiWsAuthParam(apiWsAuthParam);
        // 如果请求体设置了x-www-form-urlencoded, 进行复制
        TestApiWsRequest.ApiHttpRequestBodyParam sourceBodyParam =
            apiWsRequest.getApiWsRequestBodyParam();
        ApiWsRequestBodyParam apiWsRequestBodyParam =
            ConvertUtil.copyProperties(sourceBodyParam, ApiWsRequestBodyParam.class);
        if (Objects.equals("application/x-www-form-urlencoded", sourceBodyParam.getContentType())) {
            if (CollectionUtils.isNotEmpty(sourceBodyParam.getFormParams())) {
                apiWsRequestBodyParam.setFormParams(
                    ConvertUtil.copyProperties(
                        testApiWsParam.getApiWsRequestBodyParam().getFormParams(),
                        ApiWsRequestBodyParam.FormParam.class));
            }
        }
        String jsonBody = apiWsRequestBodyParam.getBody();
        if (StringUtils.isNotEmpty(jsonBody)) {
            apiWsRequestBodyParam.setBody(jsonBody.replace("\r\n", ""));
        }
        testApiWsParam.setApiWsRequestBodyParam(apiWsRequestBodyParam);

        // 用户填写的js脚本或者json path
        PreviewExpressRequest previewExpressRequest = saveTaskRequest.getPreviewExpressRequest();
        boolean existJsScript = StringUtils.isNotBlank(previewExpressRequest.getJsScript());
        boolean existJsonPath =
            CollectionUtils.isNotEmpty(previewExpressRequest.getExpressionParamList());
        if (existJsScript == existJsonPath) {
            throw new BusinessException("js脚本和json path必须填写并且只能填写一个");
        }
        TaskDomain.PreviewExpressRequest previewExpressParam =
            ConvertUtil.copyProperties(previewExpressRequest, TaskDomain.PreviewExpressRequest.class);
        // 如果填写的是jsonpath,进行复制
        if (existJsonPath) {
            previewExpressParam.setExpressionParamList(
                ConvertUtil.copyProperties(
                    previewExpressRequest.getExpressionParamList(),
                    TaskDomain.PreviewExpressRequest.ExpressionParam.class));
        }

        // 任务其他配置
        TaskConfigRequest taskConfigRequest = saveTaskRequest.getTaskConfigRequest();
        TaskConfigDomain taskConfigDomain =
            ApiTaskConfigConvert.convertTaskConfigDomain(taskConfigRequest);

        OfflineDevApiDomain offlineDevApiDomain = new OfflineDevApiDomain();
        if (CollectionUtils.isNotEmpty(taskConfigRequest.getTargetFields())) {
            taskConfigDomain.setTargetFields(
                ConvertUtil.copyProperties(
                    taskConfigRequest.getTargetFields(), TaskConfigDomain.TargetField.class));
        }
        if (CollectionUtils.isNotEmpty(taskConfigRequest.getFieldMappings())) {
            taskConfigDomain.setFieldMappings(
                ConvertUtil.copyProperties(
                    taskConfigRequest.getFieldMappings(), TaskConfigDomain.FieldMapping.class));
        }
        if (CollectionUtils.isNotEmpty(taskConfigRequest.getPartitions())) {
            taskConfigDomain.setPartitions(
                ConvertUtil.copyProperties(
                    taskConfigRequest.getPartitions(), TaskConfigDomain.PartitionField.class));
        }

        offlineDevApiDomain.setApiNodeType(OfflineDevApiNodeTypeEnum.WS.getNodeDesc());
        offlineDevApiDomain.setOfflineDevApiWsParam(testApiWsParam);
        offlineDevApiDomain.setTaskConfigDomain(taskConfigDomain);
        offlineDevApiDomain.setPreviewExpressRequest(previewExpressParam);
        offlineDevApiDomain.setNodeId(saveTaskRequest.getNodeId());
        offlineDevApiDomain.setNodeName(saveTaskRequest.getNodeName());
        offlineDevApiDomain.setTaskName(saveTaskRequest.getTaskName());
        offlineDevApiDomain.setProjectId(ServletUtils.getProjectId());
        offlineDevMenuNodeService.saveOrUpdateOfflineApiTask(offlineDevApiDomain);
        return true;
    }

    public Long start(Long nodeId) {
        int execType = 0;
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();
        return datadevJobService.startOfflineApiTask(nodeId, execType, projectId, userId);
    }

    public TestApiDTO test(TestApiHttpRequest testApiHttpRequest) {
        TestApiHttpParam testApiHttpParam = new TestApiHttpParam();
        testApiHttpParam.setHttpRequestMethod(testApiHttpRequest.getHttpRequestMethod());
        testApiHttpParam.setUrl(testApiHttpRequest.getUrl());
        // auth
        testApiHttpParam.setApiHttpAuthParam(
            ConvertUtil.copyProperties(
                testApiHttpRequest.getApiHttpAuthParam(), ApiHttpAuthParam.class));

        // body
        ApiHttpRequestBodyParam apiHttpRequestBodyParam =
            ConvertUtil.copyProperties(
                testApiHttpRequest.getApiHttpRequestBodyParam(), ApiHttpRequestBodyParam.class);
        if (CollectionUtils.isNotEmpty(
            testApiHttpRequest.getApiHttpRequestBodyParam().getFormParams())) {
            // 复制formparam
            apiHttpRequestBodyParam.setFormParams(
                ConvertUtil.copyProperties(
                    testApiHttpRequest.getApiHttpRequestBodyParam().getFormParams(),
                    ApiHttpRequestBodyParam.FormParam.class));
        }
        String jsonBody = apiHttpRequestBodyParam.getBody();
        if (StringUtils.isNotEmpty(jsonBody)) {
            apiHttpRequestBodyParam.setBody(jsonBody.replace("\r\n", ""));
        }
        testApiHttpParam.setApiHttpRequestBodyParam(apiHttpRequestBodyParam);

        TestApiHttpDomain testApiHttpDomain = apiHttpService.testApiHttp(testApiHttpParam);
        return ConvertUtil.copyProperties(testApiHttpDomain, TestApiDTO.class);
    }

    public TestApiDTO test(TestApiWsRequest testApiwsRequest) {
        TestApiWsParam testApiWsParam =
            ConvertUtil.copyProperties(testApiwsRequest, TestApiWsParam.class);
        // 复制认证信息
        testApiWsParam.setApiWsAuthParam(
            ConvertUtil.copyProperties(testApiwsRequest.getApiWsAuthParam(), ApiWsAuthParam.class));
        // 复制请求体
        testApiWsParam.setApiWsRequestBodyParam(
            ConvertUtil.copyProperties(
                testApiwsRequest.getApiWsRequestBodyParam(), ApiWsRequestBodyParam.class));
        com.sh.data.engine.domain.integration.api.webservice.model.domain.TestApiHttpDomain
            testApiHttpDomain = apiWsService.testApi(testApiWsParam);
        return ConvertUtil.copyProperties(testApiHttpDomain, TestApiDTO.class);
    }

    public GetServiceDTO getWsdlPortsAndMethods(GetServiceRequest getServiceRequest) {
        GetServiceParam getServiceParam =
            ConvertUtil.copyProperties(getServiceRequest, GetServiceParam.class);
        GetServiceDomain wsdlPortsAndMethods = apiWsService.getWsdlPortsAndMethods(getServiceParam);
        return ConvertUtil.copyProperties(wsdlPortsAndMethods, GetServiceDTO.class);
    }

    public UploadJarDTO uploadJar(MultipartFile multipartFile) {
        JarUploadResultDomain jarUploadResultDomain = taskConfigServiceImpl.uploadJar(multipartFile);
        return ConvertUtil.copyProperties(jarUploadResultDomain, UploadJarDTO.class);
    }

    public List<List<Object>> preview(PreviewExpressRequest previewExpressRequest) {
        boolean existJsScript = StringUtils.isNotBlank(previewExpressRequest.getJsScript());
        boolean existJsonPath =
            CollectionUtils.isNotEmpty(previewExpressRequest.getExpressionParamList());
        if (existJsScript == existJsonPath) {
            throw new BusinessException("js脚本和json path必须填写并且只能填写一个");
        }
        PreviewExpressParam previewExpressParam =
            ConvertUtil.copyProperties(previewExpressRequest, PreviewExpressParam.class);
        if (existJsonPath) {
            List<ExpressionParam> expressionParams =
                ConvertUtil.copyProperties(
                    previewExpressRequest.getExpressionParamList(), ExpressionParam.class);
            previewExpressParam.setExpressionParamList(expressionParams);
        }
        return taskConfigServiceImpl.preview(previewExpressParam);
    }

    public GetDataSourceDTO getDatabases() {
        Long projectId = ServletUtils.getProjectId();
        List<DataSourceDomain> databases = taskConfigServiceImpl.getDatabases(projectId);
        GetDataSourceDTO getDataSourceDTO = new GetDataSourceDTO();
        List<GetDataSourceDTO.DataSource> dataSources =
            ConvertUtil.copyProperties(databases, GetDataSourceDTO.DataSource.class);
        getDataSourceDTO.setDataSources(dataSources);
        return getDataSourceDTO;
    }

    public GetTargetTablesDTO getTargetTables(Long dsId) {
        List<TableInfoDomain> targetTables = taskConfigServiceImpl.getTargetTables(dsId);
        GetTargetTablesDTO getTargetTablesDTO = new GetTargetTablesDTO();
        List<GetTargetTablesDTO.Table> tables =
            ConvertUtil.copyProperties(targetTables, GetTargetTablesDTO.Table.class);
        for (GetTargetTablesDTO.Table table : tables) {
            if (StringUtils.isNotEmpty(table.getSchema())) {
                table.setDetailedTblName(String.format("%s.%s", table.getSchema(), table.getTableName()));
            }
        }
        getTargetTablesDTO.setTables(tables);
        return getTargetTablesDTO;
    }

    public GetCreateTableDDLDTO getCreateTableDDL(GetCreateTableDDLRequest getCreateTableDDLRequest) {
        String createTableDDL = taskConfigServiceImpl.getCreateTableDDL(
            ServletUtils.getProjectId(),
            getCreateTableDDLRequest.getDsId(),
            getCreateTableDDLRequest.getFields(),
            getCreateTableDDLRequest.getIsSupportRtf());
        return new GetCreateTableDDLDTO(createTableDDL);
    }

    public String saveTargetTable(SaveTargetTableRequest saveTargetTableRequest) {
        return taskConfigServiceImpl.saveTargetTable(
            ServletUtils.getProjectId(), saveTargetTableRequest.getSql(), saveTargetTableRequest.getDataSecretId());
    }

    public GetFieldsDTO getTargetTableFields(Long dsId, String tableName) {
        List<FieldInfoDomain> targetTableFields =
            taskConfigServiceImpl.getTargetTableFields(dsId, tableName);
        GetFieldsDTO getFieldsDTO = new GetFieldsDTO();
        getFieldsDTO.setFields(ConvertUtil.copyProperties(targetTableFields, GetFieldsDTO.Field.class));
        return getFieldsDTO;
    }
}
